其他
代码混淆之我见(四)
本文为看雪论坛优秀文章
看雪论坛作者ID:三十二变
.ZP1:00423026 mov [esp+114h+var_114], esi
.ZP1:00423035 mov esi, 403539h
.ZP1:0042303A sub esi, offset loc_40363D
.ZP1:00423046 not esi
.ZP1:0042304E xchg esi, [esp+114h+var_114]
= >
push 0x103
//这可以看成是模式替换与常量展开的嵌套使用
push imm
=> //模式匹配
sub esp,4
mov [esp],imm
=> //常量展开
sub esp,4
mov [esp],reg
mov reg,xxx
..... //对reg的解密
xchg [esp],reg
1)花指令
PBYTE pBuf = (PBYTE)malloc(0x10000);
PBYTE p = pBuf;
BYTE b1[] = {0xE9, 0x01, 0, 0, 0};
BYTE b2[] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
GetData(0x423000, pBuf, 0xF00);
for (int i = 0; i < 0xF00 - 5; i++) {
if (!memcmp(pBuf, b1, sizeof(b1))) {
memcpy(pBuf, b2, sizeof(b2));
}
pBuf++;
}
SetData(0x423000, p, 0xF00);
free(p);
return;
}
2)模式替换
label:
push label
add [esp],0 //重定位
jmp func
call func
jmp label
push imm32
lea esp,[esp-4] | sub esp,4
mov [esp],reg32
mov reg32,imm32
xchg [esp],reg32
push imm32
xchg reg32,Xreg32
sub esp,4 | lea esp,[esp-4]
mov [esp],Xreg32
mov Xreg32,reg32
mov reg32,[esp]
push reg32
push imm32
pop reg32
mov reg32,imm32
sub reg32,imm32
push Xreg32
mov Xreg32,imm32
push Xreg32
cmp reg32,[esp]
pushf //保存sub运算结果标志位
not [esp+4]
inc [esp+4] //neg [esp+4]
add reg32,[esp+4] //将减法转为除法
popf //取出运算标志位
lea esp,[esp+4]
xchg Xreg32,[esp]
add esp,4
sub reg32,imm32
char szAsm[64];
BYTE bCode[15];
cs_insn* pIns;
for (unsigned int i = 0; i < vIns.size(); i++) {
if (vIns[i] == NULL)
continue;
//CALL IMM32
if (!strcmp(vIns[i]->mnemonic, "push") && vIns[i]->detail->x86.operands[0].type == X86_OP_IMM && i - vIns.size() >= 3) {
if (vIns[i + 1] != NULL && vIns[i + 1] != NULL && !strcmp(vIns[i + 1]->mnemonic, "add") && !strcmp(vIns[i + 2]->mnemonic, "jmp")) {
cs_insn* pI1;
/*
push retaddr
add [esp],0
jmp calladdr
=>
call calladdr
jmp retaddr
*/
wsprintfA(szAsm, "call 0x%X", vIns[i + 2]->detail->x86.operands[0].imm);
Asm(DWORD(vIns[i]->address), szAsm, bCode);
cs_disasm(_handle, bCode, 15, vIns[i]->address, 1, &pIns);
pI1 = vIns[i];
vIns[i] = pIns;
wsprintfA(szAsm, "jmp 0x%X", pI1->detail->x86.operands[0].imm);
Asm(DWORD(vIns[i + 1]->address), szAsm, bCode);
cs_disasm(_handle, bCode, 15, vIns[i + 1]->address, 1, &pIns);
cs_free(vIns[i + 1], 1);
cs_free(vIns[i + 2], 1);
vIns[i + 2] = NULL;
vIns[i + 1] = pIns;
cs_free(pI1, 1);
}
}
...................... //省略
}
3)常量展开
sub esi,50 {esi:0}
inc esi {esi:1}
if (vIns.empty())
return;
std::vector<ContextInfo> v;
ContextInfo ct;
for (int i = X86_REG_INVALID; i <= X86_REG_ENDING; i++)
ct[i] = -1;
v.push_back(ct);
for (unsigned int i = 0; i < vIns.size() - 1; i++) {
for (int x = 0; x < vIns[i]->detail->regs_write_count; x++)
ct[vIns[i]->detail->regs_write[x]] = i;
for (int x = 0; x < vIns[i]->detail->x86.op_count; x++) {
if (vIns[i]->detail->x86.operands[x].type == X86_OP_REG && vIns[i]->detail->x86.operands[x].access & CS_AC_WRITE)
ct[vIns[i]->detail->x86.operands[x].reg] = i;
}
v.push_back(ct);
}
//我偷懒了,忽略了一些问题
/*
这是我偷懒忽略掉的情况
mov ax,2010
mov dl,al
*/
std::vector<int> vReg;
for (unsigned int i = 0; i < v.size(); i++) {
if (!(vIns[i]->detail->x86.op_count != 0 && vIns[i]->detail->x86.operands[0].type == X86_OP_REG && vIns[i]->detail->x86.operands[0].access & CS_AC_WRITE))
......
更多更详细的代码请点击阅读原文查看
4)整合结果
std::vector<DWORD> vAccess; //未访问的代码块的起始地址
std::vector<cs_insn*> vIns; //块代码
DWORD pIns = 0x423002;
BYTE bCode[15] = {0};
cs_insn* pDasm;
while (true) {
GetData(pIns, bCode, 15);
cs_disasm(_handle, bCode, 15, pIns, 1, &pDasm);
pIns += pDasm->size;
vIns.push_back(pDasm);
if (IsJxInsn(pDasm)) {
unsigned int k;
do {
k = vIns.size();
CleanNop(vIns);
CleanImm(vIns);
CleanNop(vIns);
CleanPattern(vIns);
} while (k != vIns.size());
break;
}
}
for (unsigned int i = 0; i < vIns.size(); i++)
printf("%s %s \r\n", vIns[i]->mnemonic, vIns[i]->op_str);
system("pause");
return;
...
完整代码请点击阅读原文查看
- End -
看雪ID:三十二变
https://bbs.pediy.com/user-783210.htm
进阶安全圈,不得不读的一本书
推荐文章++++
* Linux Kernel Exploit 内核漏洞学习(3)-Bypass-Smep
﹀
﹀
﹀
官方微博:看雪安全
商务合作请发邮件至:wsc@kanxue.com